package com.boss.fileapp.schedule;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.boss.fileapp.dao.AutoCronDao;
import com.boss.fileapp.entity.AgencyVerify;
import com.boss.fileapp.entity.WfActionDTO;
import com.boss.fileapp.enums.ActionTypeEnum;
import com.boss.framework.exception.AppRuntimeException;
import com.boss.sys.config.CseCommonConfiguration;
import com.boss.sys.utils.SysUtils;
import org.omg.CORBA.OBJ_ADAPTER;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.TriggerContext;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;

/**
 * <br>Title: 单位工资 自动上报类
 * <br>Description:
 * <br>Author:
 * <br>Date:
 */
@Component
public class SalaryAutoReportTask implements SchedulingConfigurer {

    private static Logger logger = LoggerFactory.getLogger(SalaryAutoReportTask.class);

    /** 是 **/
    private final int YES = 1;
    /** 否 **/
    private final int NO = 0;
    /** 自动上报标识 **/
    private final String autoReport = "1";

    /** 工作流送审接口地址 **/
    private final String WORKFLOW_ACTIONS = "/v2/workflow/actions";

    /** 根据bizKey查询流程信息接口地址 **/
    private final String WORKFLOW_INTODO = "/v2/workflow/menus/intodo?processDefKey=%s&bizKey=%s&province=%s&year=%s";

    /** 默认定时任务表达式 **/
    private String defautCron = "0 0 0 %s * ?";

    private ScheduledTaskRegistrar taskRegistrar;

    /** 定时任务集合 **/
    private ConcurrentHashMap<String, ScheduledFuture<?>> scheduledFutures = new ConcurrentHashMap<>();

    @Autowired
    private AutoCronDao autoCronDao;

    /**
     * 引入模板配置类
     */
    @Autowired
    private RestTemplate restTemplate;
    /**
     * 引入配置类
     */
    @Autowired
    private CseCommonConfiguration commonConfiguration;


    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        this.taskRegistrar = taskRegistrar;
    }

    /**
     * 修改定时任务
     * @param mofDivCode  区划
     * @param cron
     */
    public void editCronTask(String mofDivCode, String cron) {
        if (scheduledFutures.containsKey(mofDivCode)) {
            scheduledFutures.remove(mofDivCode).cancel(false);
        }
        // 添加定时任务
        ScheduledFuture scheduledFuture = addScheduled(String.valueOf(mofDivCode),
                String.valueOf(cron));
        // 将定时任务添加到数组中
        scheduledFutures.put(mofDivCode, scheduledFuture);
    }

    /**
     * 初始添加定时任务
     * @param cronList
     */
    public void initAddCronTask(List<Map<String, Object>> cronList) {
        for (Map<String, Object> cronMap: cronList) {
            // 添加定时任务
            ScheduledFuture scheduledFuture = addScheduled(String.valueOf(cronMap.get("mof_div_code")),
                    String.valueOf(cronMap.get("end_salary_time")));
            // 将定时任务添加到数组中
            scheduledFutures.put(cronMap.get("mof_div_code").toString(), scheduledFuture);
        }
    }

    /**
     * 动态添加定时任务
     * @param mofDivCode
     * @param endSalaryTime
     * @return
     */
    private ScheduledFuture addScheduled(String mofDivCode, String endSalaryTime) {
        // 定时任务执行时间
        String cron = String.format(defautCron, endSalaryTime);
        // 创建定时任务
        ScheduledFuture scheduledFuture = taskRegistrar.getScheduler().schedule(new Runnable() {
            @Override
            public void run() {
                String currentDay = String.valueOf(LocalDateTime.now().getDayOfMonth());
                if (currentDay.equals(endSalaryTime)) {
                    logger.info(mofDivCode + "定时任务执行中。。。");
                    autoReportSalary(mofDivCode);
                }
            }
        }, new Trigger() {
            @Override
            public Date nextExecutionTime(TriggerContext triggerContext) {
                return new CronTrigger(cron).nextExecutionTime(triggerContext);
            }
        });
        return scheduledFuture;
    }

    /**
     * 自动上报
     * @param mofDivCode
     */
    private void autoReportSalary(String mofDivCode) {
        // 获取所有未上报、未发送变化的未月结单位信息
        try {
            List<AgencyVerify> list = autoCronDao.getNoReportAgencyData(mofDivCode);
            if (!StringUtils.isEmpty(list) && list.size() > 0) {
                // 获取流程配置信息
                Map<String, Object> nodeMap = autoCronDao.getWorkflowNodeConfig(mofDivCode);
                if (!StringUtils.isEmpty(nodeMap) && nodeMap.size() > 0) {
                    String processDefKey = nodeMap.get("process_def_key").toString();
                    String userId = nodeMap.get("user_id").toString();
                    String firstMenuId = nodeMap.get("first_menu_id").toString();
                    for (AgencyVerify agencyVerify: list) {
                        agencyVerify.setIsAuto(autoReport);
                        // 如果单位已送审，但是未上报财政，推工作流
                        if (YES == agencyVerify.getIsSubmitInAgency()) {
                            // 获取工作流节点信息
                            logger.info(" === 获取工作流节点信息 ：" + agencyVerify);
                            WfActionDTO<AgencyVerify> wfActionDTO = new WfActionDTO();
                            wfActionDTO.setProcessDefKey(processDefKey);
                            wfActionDTO.setBusinessKeys(agencyVerify.getBizKey());
                            wfActionDTO.setProvince(mofDivCode);
                            wfActionDTO.setYear(agencyVerify.getYear());
                            String menuid = getMenuid(wfActionDTO);
                            logger.info(" === 工作流节点菜单id ：" + menuid);
                            wfActionDTO.setMenuguid(menuid);
                            // 送审
                            wfActionDTO.setActionType(ActionTypeEnum.WF_AUDIT.getActionTypeCode());
                            wfActionDTO.setBizDatas(agencyVerify);
                            wfActionDTO.setBizKeyName("bizKey");
                            wfActionDTO.setUserId(userId);
                            // 执行工作流
                            logger.info(" === 送审工作流 ：" + wfActionDTO.toString());
                            doSalaryFlow(wfActionDTO);
                        }
                        // 单位未操作，直接推工作流
                        else {
                            WfActionDTO<AgencyVerify> wfActionDTO = new WfActionDTO();
                            wfActionDTO.setMenuguid(firstMenuId);
                            // 录入并送审
                            wfActionDTO.setProcessDefKey(processDefKey);
                            wfActionDTO.setActionType(ActionTypeEnum.WF_INPUT_AUDIT.getActionTypeCode());
                            wfActionDTO.setBizDatas(agencyVerify);
                            wfActionDTO.setBizKeyName("bizKey");
                            wfActionDTO.setProvince(mofDivCode);
                            wfActionDTO.setYear(agencyVerify.getYear());
                            wfActionDTO.setUserId(userId);
                            // 执行工作流
                            logger.info(" === 录入并送审工作流 ：" + wfActionDTO.toString());
                            doSalaryFlow(wfActionDTO);
                        }
                        // 修改上报状态
                        logger.info(" === 修改单位上报状态 ：" + agencyVerify);
                        agencyVerify.setIsSubmitInAgency(YES);
                        agencyVerify.setSalaryVerifiedInAgencyCode(String.valueOf(YES));
                        agencyVerify.setIsSalarySubmit(YES);
                        autoCronDao.updateAgencyInfo(agencyVerify);
                    }
                } else {
                    throw new AppRuntimeException("未配置工作流基础信息，无法自动上报！");
                }
            }
        } catch (AppRuntimeException e) {
            logger.error(e.getMessage());
        }
    }

    /**
     * 送审工作流
     * @param wfActionDTO
     */
    private void doSalaryFlow(WfActionDTO wfActionDTO) {
        ActionTypeEnum actionType = ActionTypeEnum.toEnum(wfActionDTO.getActionType());
        logger.info("datas:" + wfActionDTO.getBizDatas() + "，processDefKey:" + wfActionDTO.getProcessDefKey() +
                "，menuguid=" + wfActionDTO.getMenuguid() + "，action" + actionType.getActionTypeCode() +
                "，actionName：" + actionType.getActionTypeName());
        if (SysUtils.isNullOrEmpty(wfActionDTO.getBizDatas())) {
            throw new AppRuntimeException("流程数据不能为空");
        }
        List<Object> lists = new ArrayList<>();
        lists.add(wfActionDTO.getBizDatas());
        //构造请求参数
        MultiValueMap<String, Object> params = new LinkedMultiValueMap<>();
        params.add("processDefKey", wfActionDTO.getProcessDefKey());
        params.add("menuguid", wfActionDTO.getMenuguid());
        params.add("actionType", actionType.getActionTypeCode());
        params.add("actionName", wfActionDTO.getActionName());
        params.add("year", wfActionDTO.getYear());
        params.add("province", wfActionDTO.getProvince());
        params.add("bizDatas", JSON.toJSONString(lists));
        params.add("bizKeyName", wfActionDTO.getBizKeyName());
        params.add("message", wfActionDTO.getMessage());
        params.add("userId", wfActionDTO.getUserId());
        logger.info("传入工作流参数 params : " + params);
        //构造实体对象
        String url = commonConfiguration.getBpmnx() + WORKFLOW_ACTIONS;
        String str = restTemplate.postForObject(url, params, String.class);
        JSONObject jsonObject = JSON.parseObject(str);
        logger.info(jsonObject.toString());
        if (!"100000".equals(jsonObject.get("rscode"))) {
            throw new AppRuntimeException((String) jsonObject.get("result"));
        }
    }

    /**
     * 获取菜单id
     * @param wfActionDTO
     * @return
     */
    private String getMenuid(WfActionDTO wfActionDTO) {
        logger.info(" 获取工作流节点信息 ： " + wfActionDTO.toString());
        String menuid = "";
        String url = commonConfiguration.getBpmnx() + String.format(WORKFLOW_INTODO, wfActionDTO.getProcessDefKey(),
                                    wfActionDTO.getBusinessKeys(), wfActionDTO.getProvince(), wfActionDTO.getYear());
        String str = restTemplate.getForObject(url, String.class);
        JSONObject jsonObject = JSON.parseObject(str);
        if ("100000".equals(jsonObject.get("rscode"))) {
            JSONArray jsonArray = jsonObject.getJSONArray("data");
            menuid =  jsonArray.getJSONObject(0).getString("menuGuid");
        } else {
            throw new AppRuntimeException((String) jsonObject.get("result"));
        }
        return menuid;
    }

    public static void main(String[] args) {
        System.out.println(LocalDateTime.now().getDayOfMonth());
    }
}
